package main

import (
	"bytes"
	"context"
	"encoding/binary"
	"fmt"
	"io"
	"os"
	"os/signal"
	"syscall"
	"time"

	"gitee.com/simonxie979/skymeta/logutil"
	"gitee.com/simonxie979/skymeta/network"
	"gitee.com/simonxie979/skymeta/uuid"
)

type Client struct {
	ctx  context.Context
	comm *network.Communicator[string]
	log  *logutil.Logger
}

func NewClient(ctx context.Context) *Client {
	s := new(Client)
	s.ctx = ctx
	s.log = logutil.NewLogger(ctx, ".", "client", "text")
	s.log.SetLevel("debug")
	s.comm = network.NewCommunicator[string](ctx, s, s.log)

	return s
}

func (s *Client) OnConnect(sessionID uint64, addr string) {
	s.log.Infof("Client", "new connection %v %v", sessionID, addr)
}

func (s *Client) OnDisconnect(sessionID uint64, err error) {
	s.log.Infof("Client", "%v disconnect with error: %v", sessionID, err)
}

func (s *Client) OnMessage(sessionID uint64, data string) {
	s.log.Infof("Client", "recive: %s", data)
}

func (s *Client) Pack(payload string, buf *bytes.Buffer) {
	headerBuf := headerBufPool.Get().(*[]byte)
	defer headerBufPool.Put(headerBuf)

	binary.BigEndian.PutUint32(*headerBuf, uint32(len(payload)))
	buf.Write(*headerBuf)
	buf.WriteString(payload)
}

func (s *Client) Unpack(reader io.Reader) (payload string, err error) {
	headerBuf := headerBufPool.Get().(*[]byte)
	defer headerBufPool.Put(headerBuf)

	_, err = io.ReadAtLeast(reader, *headerBuf, headerSize)
	if err != nil {
		return
	}

	length := binary.BigEndian.Uint32(*headerBuf)
	data := make([]byte, length)

	_, err = io.ReadFull(reader, data)

	payload = string(data)
	return
}

func (s *Client) sendLoop(sessionID uint64, index int) {
	defer func() {
		s.log.Infof("Client", "%X %3d发送消息完毕", sessionID, index)
	}()

	count := 0
	ticker := time.NewTicker(time.Second)
	for count < 10 {
		select {
		case <-s.ctx.Done():
			return
		case <-ticker.C:
			str := fmt.Sprintf("%X %3d Count:%3d", sessionID, index, count)
			s.comm.SendMsg(sessionID, str)
			count++
		}
	}
}

func RunClient(count int) {
	uuid.Init(1)

	ctx, cancel := context.WithCancel(context.Background())

	client := NewClient(ctx)
	defer client.log.Wait()
	defer client.comm.Close()
	defer cancel()

	client.log.Infof("Client", "开始")
	defer client.log.Infof("Client", "结束")

	for i := 0; i < count; i++ {
		sessionID, err := client.comm.EstablishTCP("tcp", "localhost:8888")
		if err != nil {
			client.log.Panicf("Client", "连接端口错误：%v", err)
			return
		}
		go client.sendLoop(sessionID, i)
	}

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT)
	sig := <-sigChan
	client.log.Infof("Client", "收到 %v 信号", sig)
}
